package cn.xo68.boot.web.web.exception;

import cn.xo68.boot.web.properties.WebCoreProperties;
import cn.xo68.boot.web.web.WebContext;
import cn.xo68.core.entity.JsonResponsEntity;
import cn.xo68.core.util.JsonUtil;
import cn.xo68.core.util.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * web异常处理配置
 * @author wuxie
 * @date  2018-11-30
 */
public class WebExceptionHandleConfigurer {

    private static ConcurrentMap<String, Logger> loggers=new ConcurrentHashMap<>();

    @Autowired
    protected  WebContext webContext;
    @Autowired
    protected  JsonUtil jsonUtil;
    @Autowired
    protected  WebCoreProperties webCoreProperties;

    public WebExceptionHandleConfigurer() {

    }



    protected Logger getClassLoggerByClassName(String className){
        if(!loggers.containsKey(className)){
            loggers.put(className, LoggerFactory.getLogger(className));
        }
        return loggers.get(className);
    }

    protected Logger getExceptionClassLogger(Throwable throwable){
        Logger log=null;
        if(throwable.getStackTrace().length>0){
            log=getClassLoggerByClassName(throwable.getStackTrace()[0].getClassName());
        }else{
            log=LoggerFactory.getLogger(this.getClass());
        }
        return log;
    }

    /**
     * 输出日志返回 请求地址
     * @param request
     * @param e
     * @return
     */
    protected String outLogAndReturnRequestUrl(HttpServletRequest request, Exception e){
        Logger log= getExceptionClassLogger(e);
        String requestUrl=request.getRequestURI();
        log.error("["+requestUrl+"]发生异常",e);
        if(StringTools.isEmpty(requestUrl)){
            requestUrl= "/";
        }
        return requestUrl;
    }

    protected ResponseEntity<?> returnFailJson(String error){
        return returnFailJson(error, HttpServletResponse.SC_OK);
    }

    /**
     * 输出 json结构 信息
     * @param error
     * @param httpStatus
     * @return
     */
    protected ResponseEntity<?> returnFailJson(String error, int httpStatus){
        JsonResponsEntity<Object> jsonResponseEntity = JsonResponsEntity.fail()
                .setError(error)
                .build();
        MediaType mediaType=MediaType.APPLICATION_JSON_UTF8;
        HttpHeaders headers =webContext.buildHeaders(false, null);
        return ResponseEntity
                .status(HttpServletResponse.SC_OK)
                .cacheControl(CacheControl.noCache())
                .headers(headers)
                .contentType(mediaType)
                .body(jsonUtil.toString(jsonResponseEntity));
    }

    /**
     *
     * @param request
     * @param e
     * @return
     */
    //@ExceptionHandler(Exception.class)
    public Object exceptionHandle(HttpServletRequest request, Exception e){
        String requestUrl=outLogAndReturnRequestUrl(request, e);

        boolean isResponseJson=webContext.isResponseJson(request);
        if(isResponseJson){
            return returnFailJson(e.getMessage());
        }else {
            ModelAndView mv=new ModelAndView();
            mv.addObject("title",webCoreProperties.getErrorTitle());
            if(webCoreProperties.isShowSystemError()){
                mv.addObject("error",e.getMessage());
                mv.addObject("exception", e);
            }else {
                mv.addObject("error",webCoreProperties.getErrorMessage());
                mv.addObject("exception", null);
            }
            mv.addObject("errorUrl", requestUrl);

            mv.setViewName(webCoreProperties.getErrorViewName());
            return mv;
        }
    }
}
